﻿using System;
using System.Configuration;

namespace Flagwind.Data
{
	/// <summary>
	/// 提供对应用程序数据访问提供程序的获取。
	/// </summary>
	public static class DataProviderFactory
	{
		#region 私有字段

		private static IDataProvider _defaultProvider = null;
		private readonly static object _lock = new object();

		#endregion

		#region 公共属性

		/// <summary>
		/// 默认数据访问提供者实例。
		/// <remarks>如果有事务并且有可能存在并发访问，请勿使用该属性，而是创建该类的动态实例对象。</remarks>
		/// </summary>
		public static IDataProvider DefaultProvider
		{
			get
			{
				if(_defaultProvider == null)
				{
					lock(_lock)
					{
						if(_defaultProvider == null)
						{
							_defaultProvider = GetProvider();
						}
					}
				}
				return _defaultProvider;
			}
		}

		#endregion

		#region 获取数据访问提供程序

		/// <summary>
		/// 通过配置文件获得数据访问提供程序实例。
		/// </summary>
		/// <returns>数据访问提供程序实例。</returns>
		public static IDataProvider GetProvider()
		{
			if(DataAccessSettings.Default.DataProviders.Count == 0)
				throw new Exception("未在配置节配置数据库连接信息。");

			var provider = DataAccessSettings.Default.DataProviders["default"];

			if(provider == null)
				provider = DataAccessSettings.Default.DataProviders[0];

			return provider;
		}

//		/// <summary>
//		/// 通过指定的数据连接名称获取数据访问提供程序实例。
//		/// </summary>
//		/// <param name="settingName">数据连接名称。</param>
//		/// <returns>数据访问提供程序实例。</returns>
//		public static IDataProvider GetProvider(string settingName)
//		{
//			var setting = ConfigurationManager.ConnectionStrings[settingName];
//			if(setting == null)
//			{
//				throw new Exception(string.Format("未在 connectionStrings 配置节点中找到指定的连接名称： {0}", settingName));
//			}
//			return GetProvider(setting);
//		}

		/// <summary>
		/// 根据提供程序名称和连接字符串获取数据访问提供程序实例。
		/// </summary>
		/// <param name="providerName">数据访问提供程序名称字符串。</param>
		/// <param name="connectionString">连接字符串。</param>
		/// <returns>数据访问提供程序实例。</returns>
		public static IDataProvider GetProvider(string providerName, string connectionString)
		{
			var provider = DataUtility.GetProvider(providerName);
			provider.ConnectionString = connectionString;
			return provider;
		}

		/// <summary>
		/// 根据提供程序名称和连接字符串获取数据访问提供程序实例。
		/// </summary>
		/// <param name="providerName">数据访问提供程序名称字符串。</param>
		/// <param name="connectionString">连接字符串。</param>
		/// <returns>数据访问提供程序实例。</returns>
		public static IDataProvider GetProvider(string name, string providerName, string connectionString)
		{
			var provider = DataUtility.GetProvider(providerName);
			provider.Name = name;
			provider.ConnectionString = connectionString;
			return provider;
		}

//
//		/// <summary>
//		/// 根据数据访问对象类型和程序集名称获取数据访问提供程序实例。
//		/// </summary>
//		/// <param name="providerType">数据访问提供程序类型。</param>
//		/// <param name="providerAssembly">提供程序所在程序集名称。</param>
//		/// <param name="connectionString">数据库连接字符串。</param>
//		/// <returns>数据访问提供程序实例。</returns>
//		public static IDataProvider GetProvider(string providerType, string providerAssembly, string connectionString)
//		{
//			var provider = DataUtility.GetProvider(providerType, providerAssembly);
//			provider.ConnectionString = connectionString;
//			return provider;
//		}

		/// <summary>
		/// 根据指定的配置节实例获取数据访问提供程序实例。
		/// </summary>
		/// <param name="setting">数据连接配置节点。</param>
		/// <returns>数据访问提供程序实例。</returns>
		private static IDataProvider GetProvider(ConnectionStringSettings setting)
		{
			return GetProvider(setting.ProviderName, setting.ConnectionString);
		}

		#endregion
	}
}